package org.example.t02;

import org.junit.jupiter.api.Test;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

/**
 * 自定义类加载器
 */
public class CustomClassLoader extends ClassLoader {

    /**
     * Finds the class with the specified <a href="#name">binary name</a>.
     * This method should be overridden by class loader implementations that
     * follow the delegation model for loading classes, and will be invoked by
     * the {@link #loadClass <tt>loadClass</tt>} method after checking the
     * parent class loader for the requested class.  The default implementation
     * throws a <tt>ClassNotFoundException</tt>.
     *
     * @param name The <a href="#name">binary name</a> of the class
     * @return The resulting <tt>Class</tt> object
     * @throws ClassNotFoundException If the class could not be found
     * @since 1.2
     */
    @Override
    protected Class<?> findClass(String name) throws ClassNotFoundException {
        File file = new File("D:/IDEA/study/JVM/target/test-classes/"
                        + name.replace(".", "/").concat(".class"));
        try (FileInputStream fileInputStream = new FileInputStream(file);
             ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();){
            int len = -1;
            byte[] bytes = new byte[1024];
            while((len = fileInputStream.read(bytes))!=-1){
                byteArrayOutputStream.write(bytes,0,len);
            }
            byte[] array = byteArrayOutputStream.toByteArray();
            return defineClass(name, array, 0, array.length);
        } catch (IOException e) {
            e.printStackTrace();
        }
        return super.findClass(name);
    }

    public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException, InvocationTargetException {
        CustomClassLoader customClassLoader = new CustomClassLoader();
        Class<?> loadClass = customClassLoader.loadClass("org.example.AppTest");
        Object o = loadClass.newInstance();
        Method[] methods = loadClass.getDeclaredMethods();
        for (Method method : methods) {
            if (method.getName().equals("show")) {
                method.invoke(o);
                break;
            }
        }
        System.out.println(o);
        System.out.println(loadClass.getClassLoader());
        System.out.println(o.getClass().getClassLoader());
        System.out.println(o.getClass().getClassLoader().getClass().getClassLoader());
    }
}
